/////////////////////////////////////////////////////////////////////////////
// Name:        vifunc.cpp
// Purpose:     process keyevent like vim  
// Author:      Jia Wei
// Created:     2011/12/17
// Copyright:   (c) Jia Wei
// Licence:     wxWidgets licence
/////////////////////////////////////////////////////////////////////////////

#ifdef __GNUG__
#pragma implementation "vifunc.h"
#endif


// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#if defined(CB_PRECOMP)
#include "sdk.h"
#else
#include "sdk_common.h"
#include "sdk_events.h"
#include "logmanager.h"
#endif

// includes
#include <wx/event.h>


#include "vifunc.h"
#include "debugging.h"

ViFunc ViFunc::gViFunc;

ViFunc::ViFunc()
{
    //init some params
    gMode=INSERT;
    keyCode=0;
    keyCodes=0;

    //insert mode
    MAKE_PAIRS(INSERT,NONE,0,27,&ViFunc::i_esc);//esc
    MAKE_PAIRS(INSERT,CTRL,0,'[',&ViFunc::i_esc);//ctrl-[ same as esc

    //normal mode
    MAKE_PAIRS(NORMAL,NONE,0,27,&ViFunc::n_esc);//esc
    MAKE_PAIRS(NORMAL,CTRL,0,'[',&ViFunc::n_esc);//ctrl-[ same as esc
    MAKE_PAIRS(NORMAL,NONE,0,'0',&ViFunc::n_0); //0
    MAKE_PAIRS(NORMAL,NONE,0,'1',&ViFunc::n_number);//1
    MAKE_PAIRS(NORMAL,NONE,0,'2',&ViFunc::n_number);//2
    MAKE_PAIRS(NORMAL,NONE,0,'3',&ViFunc::n_number);//3
    MAKE_PAIRS(NORMAL,NONE,0,'4',&ViFunc::n_number);//4
    MAKE_PAIRS(NORMAL,NONE,0,'5',&ViFunc::n_number);//5
    MAKE_PAIRS(NORMAL,NONE,0,'6',&ViFunc::n_number);//6
    MAKE_PAIRS(NORMAL,NONE,0,'7',&ViFunc::n_number);//7
    MAKE_PAIRS(NORMAL,NONE,0,'8',&ViFunc::n_number);//8
    MAKE_PAIRS(NORMAL,NONE,0,'9',&ViFunc::n_number);//9
    MAKE_PAIRS(NORMAL,NONE,0,MAKE_CODE('h'),&ViFunc::n_h);//h
    MAKE_PAIRS(NORMAL,NONE,0,MAKE_CODE('l'),&ViFunc::n_l);//l
    MAKE_PAIRS(NORMAL,NONE,0,MAKE_CODE('j'),&ViFunc::n_j);//j
    MAKE_PAIRS(NORMAL,NONE,0,MAKE_CODE('k'),&ViFunc::n_k);//k

    MAKE_PAIRS(NORMAL,NONE,0,MAKE_CODE('i'),&ViFunc::n_i);//i
    MAKE_PAIRS(NORMAL,SHIFT,0,'6',&ViFunc::n_sf_6); //^
    MAKE_PAIRS(NORMAL,SHIFT,0,'4',&ViFunc::n_sf_4); //$
    MAKE_PAIRS(NORMAL,SHIFT,0,MAKE_CODE('g'),&ViFunc::n_G); //G
    MAKE_PAIRS(NORMAL,NONE,0,MAKE_CODE('g'),&ViFunc::n_g); //g
    MAKE_PAIRS(NORMAL,NONE,MAKE_CODE('g'),MAKE_CODE('g'),&ViFunc::n_gg); //gg

    MAKE_PAIRS(NORMAL,CTRL,0,MAKE_CODE('f'),&ViFunc::n_ctrl_f); //ctrl-f
    MAKE_PAIRS(NORMAL,CTRL,0,MAKE_CODE('b'),&ViFunc::n_ctrl_b); //ctrl-b
    MAKE_PAIRS(NORMAL,NONE,0,MAKE_CODE('b'),&ViFunc::n_b); //b
    MAKE_PAIRS(NORMAL,NONE,0,MAKE_CODE('o'),&ViFunc::n_o); //o
    MAKE_PAIRS(NORMAL,SHIFT,0,MAKE_CODE('o'),&ViFunc::n_O); //O
    MAKE_PAIRS(NORMAL,NONE,0,MAKE_CODE('e'),&ViFunc::n_e); //e
    MAKE_PAIRS(NORMAL,NONE,0,MAKE_CODE('d'),&ViFunc::n_d); //d
    MAKE_PAIRS(NORMAL,NONE,MAKE_CODE('d'),MAKE_CODE('d'),&ViFunc::n_dd); //dd
    MAKE_PAIRS(NORMAL,SHIFT,MAKE_CODE('d'),'4',&ViFunc::n_dsf_4); //d$
    MAKE_PAIRS(NORMAL,NONE,MAKE_CODE('d'),MAKE_CODE('e'),&ViFunc::n_de); //de
    MAKE_PAIRS(NORMAL,NONE,0,MAKE_CODE('u'),&ViFunc::n_u); //u
    MAKE_PAIRS(NORMAL,CTRL,0,MAKE_CODE('r'),&ViFunc::n_ctrl_r); //ctrl-r
    MAKE_PAIRS(NORMAL,NONE,0,MAKE_CODE('x'),&ViFunc::n_x); //x
    MAKE_PAIRS(NORMAL,SHIFT,0,'5',&ViFunc::n_sf_5); //%
    MAKE_PAIRS(NORMAL,SHIFT,0,MAKE_CODE('x'),&ViFunc::n_X); //X 
    MAKE_PAIRS(NORMAL,NONE,0,MAKE_CODE('y'),&ViFunc::n_y); //y
    MAKE_PAIRS(NORMAL,NONE,MAKE_CODE('y'),MAKE_CODE('y'),&ViFunc::n_yy); //yy
    MAKE_PAIRS(NORMAL,NONE,0,MAKE_CODE('p'),&ViFunc::n_p); //p
    MAKE_PAIRS(NORMAL,NONE,0,MAKE_CODE('v'),&ViFunc::n_v); //visual mode
    MAKE_PAIRS(NORMAL,SHIFT,0,',',&ViFunc::n_bktab); //<
    MAKE_PAIRS(NORMAL,SHIFT,',',',',&ViFunc::n_bktabbktab); //<<
    MAKE_PAIRS(NORMAL,SHIFT,0,'.',&ViFunc::n_tab); //>
    MAKE_PAIRS(NORMAL,SHIFT,'.','.',&ViFunc::n_tabtab); //>>
    MAKE_PAIRS(NORMAL,NONE,0,'/',&ViFunc::n_search); //search / TODO
    MAKE_PAIRS(NORMAL,CTRL,0,MAKE_CODE('n'),&ViFunc::n_ctrl_n); //complete code ctrl-n TODO
    MAKE_PAIRS(NORMAL,CTRL,0,MAKE_CODE('p'),&ViFunc::n_ctrl_p); //complete code ctrl-p TODO
    MAKE_PAIRS(NORMAL,NONE,0,MAKE_CODE('m'),&ViFunc::n_m); //m
    MAKE_PAIRS(NORMAL,NONE,MAKE_CODE('m'),MAKE_CODE('a'),&ViFunc::n_a); //a
    MAKE_PAIRS(NORMAL,NONE,0,'~',&ViFunc::n_tom); //`
    MAKE_PAIRS(NORMAL,NONE,'~',MAKE_CODE('a'),&ViFunc::n_toma); //marker_a

    //visual mode
    MAKE_PAIRS(VISUAL,NONE,0,27,&ViFunc::v_esc);//esc
    MAKE_PAIRS(VISUAL,CTRL,0,'[',&ViFunc::v_esc);//ctrl-[ same as esc
    MAKE_PAIRS(VISUAL,NONE,0,MAKE_CODE('h'),&ViFunc::v_h);//h
    MAKE_PAIRS(VISUAL,NONE,0,MAKE_CODE('l'),&ViFunc::v_l);//l
    MAKE_PAIRS(VISUAL,NONE,0,MAKE_CODE('j'),&ViFunc::v_j);//j
    MAKE_PAIRS(VISUAL,NONE,0,MAKE_CODE('k'),&ViFunc::v_k);//k
    MAKE_PAIRS(VISUAL,NONE,0,MAKE_CODE('e'),&ViFunc::v_e);//e
    MAKE_PAIRS(VISUAL,NONE,0,MAKE_CODE('b'),&ViFunc::v_b);//b
    MAKE_PAIRS(VISUAL,SHIFT,0,'4',&ViFunc::v_sf_4);//$
    MAKE_PAIRS(VISUAL,SHIFT,0,'6',&ViFunc::v_sf_6);//^
    MAKE_PAIRS(VISUAL,NONE,0,'0',&ViFunc::v_0);//0
    MAKE_PAIRS(VISUAL,SHIFT,0,',',&ViFunc::v_bktab); //<
    MAKE_PAIRS(VISUAL,SHIFT,0,'.',&ViFunc::v_tab); //>
    MAKE_PAIRS(VISUAL,NONE,0,MAKE_CODE('y'),&ViFunc::v_y);//y
    MAKE_PAIRS(VISUAL,NONE,0,MAKE_CODE('d'),&ViFunc::v_d);//d
}

//if return FALSE,not process here,leave next.
//
bool ViFunc::execute(wxKeyEvent &event)
{
    eFKEY fkey = NONE;
    keyCode = event.GetKeyCode();
    LOGIT(wxT("vifunc::execute - customer key event,keycode: [%d]"), keyCode);
    
    if(event.m_controlDown) {
        fkey = CTRL;
    } else if(event.m_shiftDown) {
        fkey = SHIFT;
    } else {
        fkey = NONE;
    }

    if(keyCode == WXK_SHIFT && event.m_shiftDown) return TRUE;

    unsigned long key = calcKey(gMode,fkey,GET_KEYCODE(keyCodes),GET_KEYCODE(keyCode));
    if(pairs[key]) 
    {
        (this->*(pairs[key]))((wxScintilla*)event.GetEventObject());
        return TRUE;
    } 
    else if(gMode == INSERT)
    {
        return FALSE;
    } 
    else
    {
        keyCodes = 0;
        return TRUE;
    }
}


//insert mode
void ViFunc::i_esc(wxScintilla* editor)
{
    keyCodes = 0;
    gMode = NORMAL;
    editor->SetCaretForeground(wxColour(0xFF, 0x00, 0x00));
}


//normal mode
void ViFunc::n_esc(wxScintilla* editor)
{
    keyCodes = 0;
    editor->SetCaretForeground(wxColour(0xFF, 0x00, 0x00));
}
void ViFunc::n_number(wxScintilla* editor)
{
    unsigned short newline = GET_LINE(keyCodes)*10 + keyCode-'0';
    keyCodes = newline << 8 | GET_KEYCODE(keyCodes);
}
void ViFunc::n_tom(wxScintilla* editor)
{
    keyCodes = keyCode;
}
void ViFunc::n_toma(wxScintilla* editor)
{
    keyCodes = 0;
    wxString filename = getActiveFile();
    int markerid = markers[filename];
    if(markerid) {
        int line = editor->MarkerLineFromHandle(markerid);
        editor->GotoLine(line);
    }
}
void ViFunc::n_m(wxScintilla* editor)
{
    keyCodes = keyCode;
}
void ViFunc::n_a(wxScintilla* editor)
{
    keyCodes = 0;
    wxString filename = getActiveFile();
    int markerid = markers[filename];
    if(markerid) editor->MarkerDeleteHandle(markerid);
    markers[filename] = editor->MarkerAdd(editor->GetCurrentLine(),BOOKMARK_MARKER);
}
void ViFunc::n_h(wxScintilla* editor)
{
    keyCodes = 0;
    editor->CharLeft();
}
void ViFunc::n_j(wxScintilla* editor)
{
    keyCodes = 0;
    editor->LineDown();
}
void ViFunc::n_k(wxScintilla* editor)
{
    keyCodes = 0;
    editor->LineUp();
}
void ViFunc::n_i(wxScintilla* editor)
{
    keyCodes = 0;
    gMode = INSERT;
    editor->SetCaretForeground(wxColour(0x00, 0x00, 0x00));
}
void ViFunc::n_l(wxScintilla* editor)
{
    keyCodes = 0;
    editor->CharRight();
}
void ViFunc::n_0(wxScintilla* editor)
{
    if(GET_LINE(keyCodes) > 0) {
        unsigned short newline = GET_LINE(keyCodes)*10 + keyCode-'0';
        keyCodes = newline << 8 | GET_KEYCODE(keyCodes);
    } else {
        editor->Home();
        keyCodes = 0;
    }
}
void ViFunc::n_sf_6(wxScintilla* editor)
{
    keyCodes = 0;
    editor->VCHome();
}
void ViFunc::n_sf_4(wxScintilla* editor)
{
    keyCodes = 0;
    editor->LineEnd();
}
void ViFunc::n_G(wxScintilla* editor)
{
    if(GET_LINE(keyCodes) > 0) {
        editor->GotoLine(GET_LINE(keyCodes)-1);
    } else {
        editor->DocumentEnd();
    }
    keyCodes = 0;
}
void ViFunc::n_g(wxScintilla* editor)
{
    keyCodes = keyCode;
}
void ViFunc::n_bktab(wxScintilla* editor)
{
    keyCodes = keyCode;
}
void ViFunc::n_bktabbktab(wxScintilla* editor)
{
    keyCodes = 0;
    editor->BackTab();
}
void ViFunc::n_tab(wxScintilla* editor)
{
    keyCodes = keyCode;
}
void ViFunc::n_tabtab(wxScintilla* editor)
{
    keyCodes = 0;
    editor->Tab();
}
void ViFunc::n_search(wxScintilla* editor)
{
    keyCodes = 0;
}
void ViFunc::n_ctrl_n(wxScintilla* editor)
{
    keyCodes = 0;
}
void ViFunc::n_ctrl_p(wxScintilla* editor)
{
    keyCodes = 0;
}
void ViFunc::n_o(wxScintilla* editor)
{
    keyCodes = 0;
    editor->LineEnd();
    editor->NewLine();
}
void ViFunc::n_O(wxScintilla* editor)
{
    keyCodes = 0;
    editor->VCHome();
    editor->NewLine();
}
void ViFunc::n_gg(wxScintilla* editor)
{
    keyCodes = 0;
    editor->DocumentStart();
}
void ViFunc::n_y(wxScintilla* editor)
{
    keyCodes = keyCode;
}
void ViFunc::n_yy(wxScintilla* editor)
{
    keyCodes = 0;
    editor->LineCopy();
}
void ViFunc::n_p(wxScintilla* editor)
{
    keyCodes = 0;
    editor->Paste();
}
void ViFunc::n_ctrl_f(wxScintilla* editor)
{
    keyCodes = 0;
    editor->PageDown();
}

void ViFunc::n_v(wxScintilla* editor)
{
    gMode = VISUAL;
}
void ViFunc::n_dsf_4(wxScintilla* editor)
{
    keyCodes = 0;
    editor->DelLineRight();
}
void ViFunc::n_ctrl_b(wxScintilla* editor)
{
    keyCodes = 0;
    editor->PageUp();
}
void ViFunc::n_b(wxScintilla* editor)
{
    keyCodes = 0;
    editor->WordLeft();
}
void ViFunc::n_e(wxScintilla* editor)
{
    keyCodes = 0;
    editor->WordRight();
}
void ViFunc::n_de(wxScintilla* editor)
{
    keyCodes = 0;
    editor->DelWordRight();
}
void ViFunc::n_dd(wxScintilla* editor)
{
    keyCodes = 0;
    editor->LineCut();
}
void ViFunc::n_d(wxScintilla* editor)
{
    keyCodes = keyCode;
}
void ViFunc::n_u(wxScintilla* editor)
{
    keyCodes = 0;
    editor->Undo();
}
void ViFunc::n_sf_5(wxScintilla* editor)
{
    keyCodes = 0;
    int curpos = editor->GetCurrentPos();
    int bracepos = editor->BraceMatch(curpos);
    if(bracepos != -1)
    {
        editor->SetCurrentPos(bracepos);
        curpos < bracepos ? editor->SetSelectionStart(editor->GetSelectionEnd()) : editor->SetSelectionEnd(editor->GetSelectionStart());
    }
}
void ViFunc::n_x(wxScintilla* editor)
{
    keyCodes = 0;
    editor->CharRight();
    editor->DeleteBack();
}
void ViFunc::n_X(wxScintilla* editor)
{
    keyCodes = 0;
    editor->DeleteBack();
}
void ViFunc::n_ctrl_r(wxScintilla* editor)
{
    keyCodes = 0;
    editor->Redo();
}
//////////////////////////////////////////////////////////////////////

//visual mode 
void ViFunc::v_esc(wxScintilla* editor)
{
    keyCodes = 0;
    gMode = NORMAL;
    //restore select extend
    editor->SetCurrentPos(editor->GetSelectionStart());
    editor->SetCaretForeground(wxColour(0xFF, 0x00, 0x00));
}
void ViFunc::v_h(wxScintilla* editor)
{
    keyCodes = 0;
    editor->CharLeftExtend();
}
void ViFunc::v_j(wxScintilla* editor)
{
    keyCodes = 0;
    editor->LineDownExtend();
}
void ViFunc::v_k(wxScintilla* editor)
{
    keyCodes = 0;
    editor->LineUpExtend();
}
void ViFunc::v_l(wxScintilla* editor)
{
    keyCodes = 0;
    editor->CharRightExtend();
}
void ViFunc::v_e(wxScintilla* editor)
{
    keyCodes = 0;
    editor->WordRightExtend();
}
void ViFunc::v_b(wxScintilla* editor)
{
    keyCodes = 0;
    editor->WordLeftExtend();
}
void ViFunc::v_sf_4(wxScintilla* editor)
{
    keyCodes = 0;
    editor->LineEndExtend();
}
void ViFunc::v_sf_6(wxScintilla* editor)
{
    keyCodes = 0;
    editor->VCHomeExtend();
}
void ViFunc::v_0(wxScintilla* editor)
{
    keyCodes = 0;
    editor->HomeExtend();
}
void ViFunc::v_bktab(wxScintilla* editor)
{
    keyCodes = 0;
    editor->BackTab();
}
void ViFunc::v_tab(wxScintilla* editor)
{
    keyCodes = 0;
    editor->Tab();
}
void ViFunc::v_y(wxScintilla* editor)
{
    keyCodes = 0;
    editor->Copy();
    editor->SetCurrentPos(editor->GetSelectionStart());
    gMode = NORMAL;
}
void ViFunc::v_d(wxScintilla* editor)
{
    keyCodes = 0;
    editor->DeleteBack();
    gMode = NORMAL;
}
//////////////////////////////////////////////////////////////////////
